// Package models mysql数据操作类
package models

import (
	"ginmin/configs"
	"ginmin/configs/drivers"
	m "ginmin/middleware"
	"log"
	"math"
	"strconv"
	"strings"

	"github.com/xwb1989/sqlparser"
)

var funMid m.FunMiddleWare

var mysqlDb = drivers.MysqlDb
var prefix = ""

type M struct {
	Table    string
	Total    int64
	PageSize int
	Pager    int
	PageNum  int
}

func init() {
	dbConfig := configs.GetDbConfig()
	prefix = dbConfig["DB_PREFIX"]
}

// GetPrefix
// @Description: 获取表前缀
// @receiver model
// @return string
func (model *M) GetPrefix() string {
	return prefix
}

// Db
// @Description: 切表
// @receiver model
// @param name 表名
func (model *M) Db(name string) {
	model.Table = prefix + name
}

// ParseSql
// @Description: 检查sql是否正确
// @param sql sql语句
// @return error
func ParseSql(sql string) error {
	_, err := sqlparser.Parse(sql)
	if err != nil {
		log.Println(err.Error() + "\n" + "sql：" + sql)
	}
	return err
}

// GetData
// @Description: 获取单个字段
// @receiver model
// @param field 字段名
// @param where 查询条件
// @return data 返回内容
// @return err 错误信息
func (model *M) GetData(field string, where string) (data interface{}, err error) {
	sql := "SELECT " + field + " as fielddate FROM `" + model.Table + "` WHERE " + where + " limit 1"
	if err := ParseSql(sql); err != nil {
		return nil, err
	}
	rows, err := mysqlDb.Query(sql)
	if err != nil {
		log.Println(err.Error() + "\n" + "sql：" + sql)
		return nil, err
	}
	columns, _ := rows.Columns()
	scanArgs := make([]interface{}, len(columns))
	values := make([]interface{}, len(columns))
	for j := range values {
		scanArgs[j] = &values[j]
	}
	record := make(map[string]interface{})
	for rows.Next() {
		err = rows.Scan(scanArgs...)
		if err != nil {
			return nil, err
		}
		for i, v := range values {
			b, ok := v.([]byte)
			if ok {
				record[columns[i]] = string(b)
			} else {
				record[columns[i]] = v
			}
		}
	}
	defer rows.Close()
	return record["fielddate"], nil
}

// GetOne
// @Description: 获取一条数据
// @receiver model
// @param field 字段名
// @param where where条件
// @return data 返回数据
// @return err 错误信息
func (model *M) GetOne(field string, where string) (data map[string]interface{}, err error) {
	sql := "SELECT " + field + " FROM `" + model.Table + "` WHERE " + where + " limit 1"
	if err := ParseSql(sql); err != nil {
		return nil, err
	}
	rows, err := mysqlDb.Query(sql)
	if err != nil {
		log.Println(err.Error() + "\n" + "sql：" + sql)
		return nil, err
	}
	columns, _ := rows.Columns()
	scanArgs := make([]interface{}, len(columns))
	values := make([]interface{}, len(columns))
	for j := range values {
		scanArgs[j] = &values[j]
	}
	record := make(map[string]interface{})
	for rows.Next() {
		err = rows.Scan(scanArgs...)
		if err != nil {
			return nil, err
		}
		for i, v := range values {
			b, ok := v.([]byte)
			if ok {
				record[columns[i]] = string(b)
			} else {
				record[columns[i]] = v
			}
		}
	}
	defer rows.Close()
	return record, nil
}

// GetAll
// @Description: 获取多条数据
// @receiver model
// @param str 参数(field string, where string, page int, size int, order string)
// @return data 返回数据
// @return err 错误信息
func (model *M) GetAll(str ...any) (data map[int]map[string]interface{}, err error) {
	field, where, page, size, order, limit := "*", "1=1", 0, 10, "id desc", ""
	if len(str) >= 1 {
		field = m.ToString(str[0])
	}
	if len(str) >= 2 {
		where = m.ToString(str[1])
	}
	if len(str) >= 3 {
		page = m.ToInt(str[2])
	}
	if len(str) >= 4 {
		size = m.ToInt(str[3])
	}
	if len(str) >= 5 {
		order = m.ToString(str[4])
	}

	model.Total = model.GetCount(where)
	if page > 0 {
		limit = " limit " + strconv.Itoa((page-1)*size) + "," + strconv.Itoa(size)
		model.PageNum = m.ToInt(math.Ceil(m.ToFloat64(model.Total) / m.ToFloat64(size)))
		if model.PageNum <= 1 {
			model.PageNum = 1
		}
	} else {
		page = 1
		model.PageNum = 1
	}
	model.PageSize = size
	model.Pager = page
	sql := "SELECT " + field + " FROM `" + model.Table + "` WHERE " + where + " order by " + order + limit
	if err := ParseSql(sql); err != nil {
		return nil, err
	}
	rows, err := mysqlDb.Query(sql)
	if err != nil {
		log.Println(err.Error() + "\n" + "sql：" + sql)
		return nil, err
	}
	columns, _ := rows.Columns()
	vals := make([]interface{}, len(columns))
	scans := make([]interface{}, len(columns))
	for k := range vals {
		scans[k] = &vals[k]
	}
	i := 0
	result := make(map[int]map[string]interface{})
	for rows.Next() {
		err = rows.Scan(scans...)
		if err != nil {
			return nil, err
		}
		row := make(map[string]interface{})
		for k, v := range vals {
			b, ok := v.([]byte)
			if ok {
				row[columns[k]] = string(b)
			} else {
				row[columns[k]] = v
			}
		}
		result[i] = row
		i++
	}
	defer rows.Close()
	return result, nil
}

// GetSql
// @Description: 执行sql查询
// @receiver model
// @param sql sql语句
// @return data 返回数据
// @return err
func (model *M) GetSql(sql string) (data map[int]map[string]interface{}, err error) {
	if err := ParseSql(sql); err != nil {
		return nil, err
	}
	rows, err := mysqlDb.Query(sql)
	if err != nil {
		log.Println(err.Error() + "\n" + "sql：" + sql)
		return nil, err
	}
	columns, _ := rows.Columns()
	vals := make([]interface{}, len(columns))
	scans := make([]interface{}, len(columns))
	for k := range vals {
		scans[k] = &vals[k]
	}
	i := 0
	result := make(map[int]map[string]interface{})
	for rows.Next() {
		err = rows.Scan(scans...)
		if err != nil {
			return nil, err
		}
		row := make(map[string]interface{})
		for k, v := range vals {
			b, ok := v.([]byte)
			if ok {
				row[columns[k]] = string(b)
			} else {
				row[columns[k]] = v
			}
		}
		result[i] = row
		i++
	}
	defer rows.Close()
	return result, nil
}

// GetCount
// @Description: 获取总数
// @receiver model
// @param where 查询条件
// @return int64
func (model *M) GetCount(where string) int64 {
	count, err := model.GetData("count(*)", where)
	if err != nil {
		return 0
	}
	_coutn := m.ToInt64(count)
	return _coutn
}

// GetSum
// @Description: 求和
// @receiver model
// @param field 字段名
// @param where 查询条件
// @return float64
func (model *M) GetSum(field string, where string) float64 {
	sum, err := model.GetData("sum("+field+")", where)
	if err != nil {
		return 0
	}
	_sum := m.ToFloat64(sum)
	return _sum
}

// Add
// @Description: 插入数据
// @receiver model
// @param data 要插入的数据
// @return id 返回自增id
// @return err
func (model *M) Add(data map[string]interface{}) (id int64, err error) {
	var field, value []string
	for key := range data {
		field = append(field, "`"+key+"`")
		value = append(value, "'"+m.ToString(data[key])+"'")
	}
	sql := "INSERT INTO `" + model.Table + "`(" + strings.Join(field, ",") + ") VALUES (" + strings.Join(value, ",") + ")"
	if err := ParseSql(sql); err != nil {
		return 0, err
	}
	result, err := mysqlDb.Exec(sql)
	if nil != err {
		log.Println(err.Error() + "\n" + "sql：" + sql)
		return 0, err
	}
	return result.LastInsertId()
}

// Edit
// @Description: 修改数据
// @receiver model
// @param data 要修改的数据
// @param where 查询条件
// @return state 返回受影响数量
// @return err
func (model *M) Edit(data map[string]interface{}, where string) (state int64, err error) {
	var field []string
	for key := range data {
		field = append(field, "`"+key+"`='"+m.ToString(data[key])+"'")
	}
	sql := "UPDATE `" + model.Table + "` SET " + strings.Join(field, ",") + " WHERE " + where
	if err := ParseSql(sql); err != nil {
		return 0, err
	}
	result, err := mysqlDb.Exec(sql)
	if nil != err {
		log.Println(err.Error() + "\n" + "sql：" + sql)
		return 0, err
	}
	id, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}
	return id, err
}

// Del
// @Description: 删除数据
// @receiver model
// @param where 查询条件
// @return state 返回删除条数
// @return err
func (model *M) Del(where string) (state int64, err error) {
	sql := "DELETE FROM `" + model.Table + "` WHERE " + where
	if err := ParseSql(sql); err != nil {
		return 0, err
	}
	result, err := mysqlDb.Exec(sql)
	if nil != err {
		log.Println(err.Error() + "\n" + "sql：" + sql)
		return 0, err
	}
	id, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}
	return id, err
}
